//
//  main.m
//  C07_指针
//
//  Created by dllo on 15/11/25.
//  Copyright © 2015年 dllo. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Function.h"

int main(int argc, const char * argv[]) {

#pragma mark - 知识点1 C语言指针的概念

    /** 指针就是内存地址,通过指针同样可以访问内存中的内容 */
    
#pragma mark - 知识点2 指针变量的定义和使用
    
    /** 定义一个指针变量 */
    
    /** 
     * 指针变量p, 表示将访问一个地址之上4个字节的内存空间
     * NULL 的含义是: 将p指向了0 * 0 地址(空指针)
     */
//    int *p = NULL;
//    
//    long *p2 = NULL;
//    
    /** 指针变量p本身也需要在内存中保存,指针变量占用的内存字节数, 取决于系统, 64位系统占8个字节, 32位系统占4个字节 */
    
#pragma mark - 知识点3 指针的算数运算(& 运算符和 * 运算符)
#if 0
    /** & 的使用. 作用: 取出内存地址(取址符) */
    int a = 100;
    
    int *p = NULL;   /**< 定义一个指针, 指向空 */
    
    p = &a;   /**< 将指针p指向变量a的地址 */
    
    printf("p : %p\n", p);  /**< 输出p的地址 */
    printf("a : %p\n", &a);  /**< 输出a的地址 */
    
    /** * 符号: 取出 指针指向的内存地址中的内容(取值符) */
    
    printf("%d\n", *p);
    
    *p = 201;   /** 相当于 a = 201 */
    printf("%d\n", *p);
    
//    int b = 200;
//    short *ps = &b;
//    printf("%hd\n", *ps);
    
    int c = 300;
    int *p3 = NULL;
    p3 = &c;
    ++p3;
    printf("p3: %p\n", p3);
    printf("++p3:%p\n", ++p3);  // 加4个字节
    
#endif
    /** 1.交换两个int类型的变量的值 用指针实现 */
#if 0
    int a = 1;
    int b = 2;
    
    int *p = NULL;
    int *p1 = NULL;
    
    p = &a;
    p1 = &b;
    
    int temp = *p;
    a = *p1;
    b = temp;
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);

    /** 用函数实现练习1,即交换两个int类型变量值 */
    int a = 1;
    int b = 2;
    exchangeTwoNumber(&a, &b);
    printf("a = %d\nb = %d\n", a, b);
#endif

#pragma mark - 知识点4 指针和数组的关系
#if 0
    int array[5] = {1, 2, 3, 4, 5};
    
    int *p = NULL;       /**< p + 1, 访问后4个字节的内容 */
    int (*p2)[5] = NULL;    /**> p2 + 1, 访问后20个字节内容,相当于一个数组的长度 */
    
    p = array;
    p2 = &array;
    
    printf("p:%p\n", p);
    printf("arr:%p\n", array);       /**< 数组名 */
    printf("arr:%p\n", &array);      /**< 数组的首地址 */
    printf("arr:%p\n", &array[0]);   /**< 第一个元素的首地址 */
#endif
    /** 结论:数组名即是数组的首地址,也是第一个元素的首地址!!!!! */
    
    /** 通过指针,遍历数组 */
#if 0
    int array[5] = {1, 2, 3, 4, 5};
    int *p = NULL;
    p = array;
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(p + i));
    }
    
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(p++));
    }
    
    /** 扩展内容 */
    int *point[5];  /**< 指针数组 */
    int (*point2)[5]; /**< 数组指针 */

    /** 冒泡排序,用指针来实现 */
    int array[5] = {3, 5, 1, 2, 4};
    int *p = NULL;
    int temp = 0;
    p = array;
    for (int i = 0; i < 5 - 1; i++) {
        for (int j = 0; j < 5 - i - 1; j++) {
            if (*(p + j) > *(p + j + 1)) {
                temp = *(p + j);
                *(p + j) = *(p + j + 1);
                *(p + j + 1) = temp;
            }
            
        }
    }
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(p + i));
    }
    printf("\n");
    

    /** 指针作为函数的参数 */
    /** 使用函数实现冒泡排序 */
    int array[5] = {1, 3, 5, 4, 2};
    int *p = array;
    sortArr(p, 5);
    sortArr(array, 5);  /**< array数组名就是首地址 */
#endif
    

#pragma mark - 知识点5 指针和字符串的关系
    
//    printf("<#const char *restrict#>", <#...#>);
//    strcpy(<#char *#>, <#const char *#>);
    
#if 0
    /** const 修饰词的作用 */
    int a = 100;
    a = 101;
    const int b = 200;
 //   b = 201;  /**< 经过const修饰的变量不能修改,起到保护作用 */
#endif
#if 0
    /** 使用指针输出字符串(while) */
    /** 方法一 */
    char string[] = "iphone";
    char *p = string;  /** 指针指向字符串首地址 */
    int i = 0;
    while (*(p + i) != '\0') {
        printf("%c", *(p + i));
        i++;
    }
    /** 方法二 */
    while (*p) {
        printf("%c ", *(p++));
    }

    
    /** 使用指针输出字符串(for) */
    char string[] = "iphone";
    char *p = string;  /** 指针指向字符串首地址 */
    for (int i = 0; i < strlen(string); i++) {
        printf("%c", *(p + i));
    }
    printf("\n");
    
#endif 
    
    /** 通过指针计算字符串的长度 */
    char string[] = "iphone";
    char *p = string;
    int count = 0;
    while (*p) {
        count++;
        p++;
    }
    printf("count = %d\n", count);
    
    
    
    return 0;
}
